/* ****************************************************************************
 *
 * Copyright (c) Microsoft Corporation. 
 *
 * This source code is subject to terms and conditions of the Microsoft Public License. A 
 * copy of the license can be found in the License.html file at the root of this distribution. If 
 * you cannot locate the  Microsoft Public License, please send an email to 
 * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
 * by the terms of the Microsoft Public License.
 *
 * You must not remove this notice, or any other, from this software.
 *
 * THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
 * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
 * PARTICULAR PURPOSE.
 * ***************************************************************************/


#include "stdafx.h"
#include <pgl/core/PGLPave.h>
#include <pgl/core/PGLPavePropPage.h>
#include <pgl/core/PGLDataTypes.h>
#include <pgl/core/PGLDataVectors.h>

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

PGL_IMPLEMENT_DYNCREATE(CPGLPave, CPGLLine);
PGL_IMPLEMENT_SCRIPTING(Pave);

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

//! Save settings
void CPGLPave::SerializeXML(CPGLArchive& ar)
{
	static const TCHAR szTag[] = _T("CPGLPave");
	CString str;

	markup::CMarkupArchive& xml = *((markup::CMarkupArchive*)ar.GetMarkup());
	if(ar.IsStoring())
	{
		xml.AddChildElem(szTag);
		xml.AddChildAttrib(_T("Name"),GetName());
		xml.IntoElem();

			/////////////////////////////////////////////////////////
			// Adding base class
			CPGLLine::SerializeXML(ar);

			/////////////////////////////
			// Area2D
			m_rArea.SerializeXML(ar);

			// border size
			xml.AddChildElem(_T("BorderSize"));
			xml.IntoElem();
				xml.AddChildElemEx(_T("Left"), m_rBorderSize.left);
				xml.AddChildElemEx(_T("Bottom"), m_rBorderSize.bottom);
				xml.AddChildElemEx(_T("Right"), m_rBorderSize.right);
				xml.AddChildElemEx(_T("Top"), m_rBorderSize.top);
			xml.OutOfElem();

			// border size
			xml.AddChildElem(_T("InsideBorderSize"));
			xml.IntoElem();
				xml.AddChildElemEx(_T("Left"), m_rInsideBorderSize.left);
				xml.AddChildElemEx(_T("Bottom"), m_rInsideBorderSize.bottom);
				xml.AddChildElemEx(_T("Right"), m_rInsideBorderSize.right);
				xml.AddChildElemEx(_T("Top"), m_rInsideBorderSize.top);
			xml.OutOfElem();

			// adding border type
			switch(m_eBorderType)
			{
			case BorderNone:
				str=_T("none");
				break;
			case BorderPlain:
				str=_T("plain");
				break;
			case BorderLowerLeftShadow:
				str=_T("shadowll");
				break;
			case BorderLowerRightShadow:
				str=_T("shadowlr");
				break;
			case BorderUpperLeftShadow:
				str=_T("shadowul");
				break;
			case BorderUpperRightShadow:
				str=_T("shadowur");
				break;
			}
			xml.AddChildElem(_T("BorderType"),str);

		xml.OutOfElem();
	}
	else
	{
		if  (!xml.FindChildElem(szTag))
				return;

		xml.IntoElem();
			/////////////////////////////////////////////////////////
			// Adding base class
			CPGLLine::SerializeXML(ar);

			/////////////////////////////
			// Area2D
			m_rArea.SerializeXML(ar);

			// border size box
			xml.ResetChildPos();
			if (xml.FindChildElem(_T("BorderSize")))
			{
				xml.IntoElem();
					if (xml.FindChildElem(_T("Left")))
						m_rBorderSize.left=xml.GetChildDataDouble();

					xml.ResetChildPos();
					if (xml.FindChildElem(_T("Bottom")))
						m_rBorderSize.bottom=xml.GetChildDataDouble();

					xml.ResetChildPos();
					if (xml.FindChildElem(_T("Right")))
						m_rBorderSize.right=xml.GetChildDataDouble();

					xml.ResetChildPos();
					if (xml.FindChildElem(_T("Top")))
						m_rBorderSize.top=xml.GetChildDataDouble();
				xml.OutOfElem();
			}

			// inside border size box
			xml.ResetChildPos();
			if (xml.FindChildElem(_T("InsideBorderSize")))
			{
				xml.IntoElem();
					if (xml.FindChildElem(_T("Left")))
						m_rInsideBorderSize.left=xml.GetChildDataDouble();

					xml.ResetChildPos();
					if (xml.FindChildElem(_T("Bottom")))
						m_rInsideBorderSize.bottom=xml.GetChildDataDouble();

					xml.ResetChildPos();
					if (xml.FindChildElem(_T("Right")))
						m_rInsideBorderSize.right=xml.GetChildDataDouble();

					xml.ResetChildPos();
					if (xml.FindChildElem(_T("Top")))
						m_rInsideBorderSize.top=xml.GetChildDataDouble();
				xml.OutOfElem();
			}

			// adding border type
			if (xml.FindChildElem(_T("BorderType")))
			{
				str=xml.GetChildData();
				if (str==_T("none"))
				{
					m_eBorderType=BorderNone;
				}
				else if (str == _T("plain"))
				{
					m_eBorderType=BorderPlain;
				}
				else if (str == _T("shadowll"))
				{
					m_eBorderType=BorderLowerLeftShadow;
				}
				else if (str == _T("shadowlr"))
				{
					m_eBorderType=BorderLowerRightShadow;
				}
				else if (str == _T("shadowul"))
				{
					m_eBorderType=BorderUpperLeftShadow;
				}
				else if (str == _T("shadowur"))
				{
					m_eBorderType=BorderUpperRightShadow;
				}
			}

		xml.OutOfElem();
	}
}


#ifdef _DEBUG
void CPGLPave::Dump( CDumpContext& dc ) const
{
    // call base class function first
    CPGLLine::Dump( dc );

}
void CPGLPave::AssertValid() const
{
    // call inherited AssertValid first
    CPGLLine::AssertValid();

} 
#endif


void CPGLPave::AddPropertyPage(CPropertySheet* pPropSheet)
{
	ASSERT_VALID(pPropSheet);
	// call own functions
	CPGLPavePropPage* propPage=new CPGLPavePropPage(this);
	pPropSheet->AddPage(propPage);

	// first call base class function
	CPGLLine::AddPropertyPage(pPropSheet);
}

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CPGLPave::CPGLPave(const CPGLColor& _FrontColor, const CPGLColor& _FillColor, EPaveBorderType eBorderType)
: CPGLLine(_FrontColor,_FillColor), m_rBorderSize(5,5,5,5),m_rInsideBorderSize(10,10,10,10)
{
	m_eBorderType = eBorderType;

	PreparePropertyMap();
}

CPGLPave::~CPGLPave()
{

}

CPGLPave& CPGLPave::operator = (const CPGLPave& p)
{
	if (&p != this)
	{
		this->CPGLLine::operator = (p);

		m_eBorderType = p.m_eBorderType; 
		m_rBorderSize = p.m_rBorderSize;
		m_rInsideBorderSize = p.m_rInsideBorderSize;
		m_rArea = p.m_rArea;
	}
	return *this;
}

CPGLRectD CPGLPave::GetInsideWorldBBox(const gfxinterface::CGfxInterface& gfx) const
{
	CPGLRectD rIn = m_rArea.GetWorldBBox(gfx);

//	rIn.left = gfx.NormBBoxToWorldx(m_rBBox.left);
//	rIn.right = gfx.NormBBoxToWorldx(m_rBBox.right);
//	rIn.bottom = gfx.NormBBoxToWorldy(m_rBBox.bottom);
//	rIn.top = gfx.NormBBoxToWorldy(m_rBBox.top);

	if (m_eBorderType != BorderNone)
	{
		rIn.left+= gfx.BBToWorldAbsx(m_rBorderSize.left + m_rInsideBorderSize.left);
		rIn.bottom+= gfx.BBToWorldAbsy(m_rBorderSize.bottom  + m_rInsideBorderSize.bottom);
		rIn.right-= gfx.BBToWorldAbsx(m_rBorderSize.right  + m_rInsideBorderSize.right);
		rIn.top-= gfx.BBToWorldAbsy(m_rBorderSize.top  + m_rInsideBorderSize.top);
	}

	return rIn;
}

void CPGLPave::PlotGfx(gfxinterface::CGfxInterface& gfx)
{
	using namespace gfxinterface;

	if (!IsVisible())
		return;

	if (!IsInLayer(gfx.GetLayer()))
		return;

	GFX_ADDCOMMENT(gfx, "---- PlotGfx PGLPave: Starting ----");
	// setting line state...
	SetLineState(gfx);
	MakeFrontColorCurrent(gfx);

	CPGLRectD rBBox = m_rArea.GetWorldBBox(gfx);
	if (GetFillBrush())
	{
		GetFillBrush()->SetBBox( rBBox );
		GetFillBrush()->MakeCurrentFill(gfx);
	}
	else
		gfx.SetFillColor(1,1,1,0);

	// precomputing values...
	double llx=rBBox.left;
	double dpllx=gfx.BBToWorldAbsx(m_rBorderSize.left);
	double bllx=llx+dpllx ;

	double lly=rBBox.bottom;
	double dplly=gfx.BBToWorldAbsy(m_rBorderSize.bottom);
	double blly=lly+dplly;

	double urx=rBBox.right;
	double dpurx=gfx.BBToWorldAbsx(m_rBorderSize.right);
	double burx=urx - dpurx;

	double ury=rBBox.top;
	double dpury=gfx.BBToWorldAbsy(m_rBorderSize.top);
	double bury=ury - dpury;

	CPGLVectorF vX;
	CPGLVectorF vY;

	// draw borders
	static SPointD sShadowSize; 
	switch(m_eBorderType)
	{
	case BorderNone:
		gfx.DrawRect(llx,lly, urx,ury,RectTypeFilled | RectTypeNoContour); 
		break;
	case BorderLine:
		gfx.DrawRect(bllx,blly,burx,bury, RectTypeFilled); 
		break;

	case BorderPlain:
		gfx.DrawRect(bllx,blly,burx,bury, RectTypeFilled | RectTypeNoContour); 

		vX.resize(10);	vY.resize(10);
		vX[0]=(float)llx;	vY[0]=(float)lly;
		vX[1]=(float)urx;	vY[1]=(float)lly;
		vX[2]=(float)urx;	vY[2]=(float)ury;
		vX[3]=(float)llx;	vY[3]=(float)ury;
		vX[4]=(float)llx;	vY[4]=(float)lly;
		vX[5]=(float)bllx;	vY[5]=(float)blly;
		vX[6]=(float)bllx;	vY[6]=(float)bury;
		vX[7]=(float)burx;	vY[7]=(float)bury;
		vX[8]=(float)burx;	vY[8]=(float)blly;
		vX[9]=(float)bllx;	vY[9]=(float)blly;
		// filling borders
		SetFrontToFillColor(gfx, 0.3f); 
		gfx.DrawLineStrip(vX,vY,LineTypeFilled | 	LineTypeNoContour 
					| LineTypeClosed );
		break;
	case BorderEmboss:
		break;
	case BorderSunken:
		break;

	case BorderLowerLeftShadow:
		gfx.DrawRect(bllx,blly,burx,bury, gfxinterface::RectTypeFilled); 

		vX.resize(6);		vY.resize(6);
		vX[0]=(float)llx;			vY[0]=(float)(bury-dplly);
		vX[1]=(float)llx;			vY[1]=(float)lly;
		vX[2]=(float)(burx-dpllx);	vY[2]=(float)lly;
		vX[3]=(float)(burx-dpllx);	vY[3]=(float)blly;
		vX[4]=(float)bllx;			vY[4]=(float)blly;
		vX[5]=(float)bllx;			vY[5]=(float)(bury-dplly);
		SetFrontToFillColor(gfx, 0.3f); 
		gfx.DrawLineStrip(vX,vY,LineTypeFilled | LineTypeNoContour | LineTypeClosed );

		break;

	case BorderLowerRightShadow:
		sShadowSize=SPointD(m_rBorderSize.right, m_rBorderSize.bottom);
		gfx.DrawRect(bllx,blly,burx,bury, RectTypeFilled | RectTypeShadowLowerRight , sShadowSize); 
/*
		vX.resize(6);	vY.resize(6);
		vX[0]=bllx+dpurx;	vY[0]=lly;
		vX[1]=urx;			vY[1]=lly;
		vX[2]=urx;			vY[2]=bury-dplly;
		vX[3]=burx;			vY[3]=bury-dplly;
		vX[4]=burx;			vY[4]=blly;
		vX[5]=bllx+dpurx;	vY[5]=blly;
		SetFrontToFillColor(gfx, 0.3f); 
		gfx.DrawLineStrip(vX,vY,gfxinterface::LineTypeFilled | 	gfxinterface::LineTypeNoContour 
					| gfxinterface::LineTypeClosed );
*/				
		break;

	case BorderUpperRightShadow:
		gfx.DrawRect(bllx,blly,burx,bury, gfxinterface::RectTypeFilled); 

		vX.resize(6);	vY.resize(6);
		vX[0]=(float)(bllx+dpurx);	vY[0]=(float)ury;
		vX[1]=(float)urx;			vY[1]=(float)ury;
		vX[2]=(float)urx;			vY[2]=(float)(blly+dpury);
		vX[3]=(float)burx;			vY[3]=(float)(blly+dpury);
		vX[4]=(float)burx;			vY[4]=(float)bury;
		vX[5]=(float)(bllx+dpurx);	vY[5]=(float)bury;
		SetFrontToFillColor(gfx, 0.3f); 
		gfx.DrawLineStrip(vX,vY,gfxinterface::LineTypeFilled | 	gfxinterface::LineTypeNoContour 
					| gfxinterface::LineTypeClosed );
				
		break;

	case BorderUpperLeftShadow:
		gfx.DrawRect(bllx,blly,burx,bury, gfxinterface::RectTypeFilled); 

		vX.resize(6);		vY.resize(6);
		vX[0]=(float)llx;			vY[0]=(float)(blly+dpury);
		vX[1]=(float)llx;			vY[1]=(float)ury;
		vX[2]=(float)(burx-dpllx);	vY[2]=(float)ury;
		vX[3]=(float)(burx-dpllx);	vY[3]=(float)bury;
		vX[4]=(float)bllx;			vY[4]=(float)bury;
		vX[5]=(float)bllx;			vY[5]=(float)(blly+dpury);
		SetFrontToFillColor(gfx, 0.3f); 
		gfx.DrawLineStrip(vX,vY,gfxinterface::LineTypeFilled | 	gfxinterface::LineTypeNoContour 
					| gfxinterface::LineTypeClosed );
		break;
	}

	GFX_ADDCOMMENT(gfx, "---- PlotGfx PGLPave: Finished ----");
}

void CPGLPave::GrowInsideBBAbsToOutsideNormBBox(gfxinterface::CGfxInterface &gfx, double dBBWidth, double dBBHeight)
{
	CPGLRectD rTotBorder=GetTotalBorderSize();
	dBBWidth += rTotBorder.left + rTotBorder.right;
	dBBHeight += rTotBorder.bottom + rTotBorder.top;

	m_rArea.Resize(gfx, dBBWidth, dBBHeight, CPGLArea2D::CoordBB);
}

CPGLRectD CPGLPave::GetTotalBorderSize() const
{	
	if (m_eBorderType == BorderNone)
		return m_rInsideBorderSize;
	else
		return m_rBorderSize+m_rInsideBorderSize;
};


void CPGLPave::PreparePropertyMap()
{
	using namespace std;
	static bool bLoaded(false);
	
	if (bLoaded)
		return;
	bLoaded=true;

	CPGLLine::PreparePropertyMap();

	m_mProps[_T("Pave.bordertype")]=PropertyPair(PavePropBorderType, _T("Border  type:\r\n\tnone,\r\n\tline, simple line\r\n\tplain, plain border,\r\n\tlls, lower left shadow,\r\n\tlrs, lower right shadow,\r\n\turs, upper right shadow,\r\n\tuls, upper left shadow,\r\n"));
}

bool CPGLPave::SetProperty( LPCTSTR szProp, LPCTSTR szValue)
{
	if (CPGLLine::SetProperty(szProp, szValue))
		return true;

	CString sv(szValue);	
	sv.MakeLower();

	switch( StringToPaveProp( szProp ))
	{
	case PavePropBorderType:
		if (sv==_T("none"))
			SetBorderType( BorderNone);
		else if (sv==_T("plain"))
			SetBorderType( BorderPlain);
		else if (sv==_T("lls"))
			SetBorderType( BorderLowerLeftShadow);
		else if (sv==_T("uls"))
			SetBorderType( BorderUpperLeftShadow);
		else if (sv==_T("lrs"))
			SetBorderType( BorderLowerRightShadow);
		else if (sv==_T("urs"))
			SetBorderType( BorderUpperRightShadow);

		return true;
	default:
		return false;
	};
}

bool CPGLPave::Get( LPCTSTR szProp, CString& str)
{
	if(CPGLLine::Get(szProp, str))
		return true;

	return false;
}
